home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / opbonus.arc / WFIELD.ARC / WFIELD4.PAS < prev   
Pascal/Delphi Source File  |  1991-03-20  |  19KB  |  668 lines

  1. {$V-}
  2.  
  3. (*
  4.    WFIELD4
  5.    -------
  6.    This program demonstrates several neat tricks made possible by the features
  7.    added in Object Professional 1.01:
  8.  
  9.      - a menu embedded within another object derived from a command window
  10.      - a scrolling entry screen embedded within a regular entry screen
  11.      - storing a parent window and all its children within a stream
  12.      - reloading a parent window and its children from a stream
  13.  
  14.    Points worth noting:
  15.  
  16.    1) Defining TestStream (by removing the '.' before the '$') causes the
  17.       program to be compiled in such a way that the entry screen and all its
  18.       children are instantiated, stored in the stream, then reinstantiated by
  19.       rereading them from the stream. Note, however, that SES and MM are no
  20.       longer valid objects once ES has been reread from the stream. Child
  21.       windows are always allocated dynamically on the heap when they are read
  22.       back from the stream. That's why the pointer variable 'MP^' is used to
  23.       refer to the menu, rather than 'MM'.
  24.  
  25.    2) The scrolling entry screen (the child) is attached to the main entry
  26.       screen (the parent) using AddWindowField. The menu is not a field,
  27.       however, so it must be attached using the AddChild method.
  28.  
  29.    3) The menu can be activated/deactivated by pressing <F10>. In this
  30.       do-nothing demo, selecting any menu item button outside the menu simply
  31.       returns you to where you were before the menu was activated. Clicking
  32.       the left mouse button outside the menu also returns you to where you
  33.       were before, unless the mouse was clicked on a particular field. Notice
  34.       that EraseAllSubMenus must be called when the menu is deactivated to
  35.       insure that the submenus don't get overwritten by one of the fields in
  36.       the parent entry screen.
  37.  
  38.    4) From within the main entry screen, the mouse can be used to select
  39.       the child window, the menu, the "exit" hot spot, as well as any field
  40.       in the entry screen. Note, however, that when you "jump" into the child
  41.       entry screen, the cursor moves to the field in the entry screen that was
  42.       current the last time you left.
  43.  
  44.    5) Notice that the InvokeMenu routine calls EntryScreen.EvaluateCommand,
  45.       which according to the manual is supposed to be called only from within
  46.       a post-edit routine. In general, the manual is correct on that point,
  47.       but in the case of ccMouseSel it is safe to evaluate the command outside
  48.       of a post-edit routine.
  49.  
  50.    6) The scrolling entry screen is both a field in the main entry screen and
  51.       an entry screen in its own right. You can move in and out of the main
  52.       entry screen using the basic field movement commands (<Enter>, <Tab>,
  53.       <ShTab>, <Up>, <Down>), but once you are in the child entry screen the
  54.       other field movement commands (<PgUp>, <PgDn>, <CtrlPgUp>, <CtrlPgDn>)
  55.       are restricted to moving the cursor around the child window.
  56.  
  57.    7) In the scrolling entry screen, the Total field on each row is a
  58.       protected field whose value is calculated dynamically by the post-edit
  59.       routine.
  60.  
  61.    8) The wNoCoversBuffer option is used for the ScrollingEntryScreen field
  62.       to limit memory usage.
  63.  
  64. *)
  65.  
  66. {.$DEFINE TestStream}
  67.  
  68. program WFIELD4;
  69.  
  70. {$I OPDEFINE.INC}
  71.  
  72. uses
  73.   Dos,
  74.   OpInline,
  75.   OpString,
  76.   OpRoot,
  77.   OpCrt,
  78.   {$IFDEF UseMouse}
  79.   OpMouse,
  80.   {$ENDIF}
  81.   OpAbsFld,
  82.   OpCmd,
  83.   OpField,
  84.   OpFrame,
  85.   OpWindow,
  86.   OpSelect,
  87.   OpEntry,
  88.   OpMenu;
  89.  
  90.   {$IFDEF UseMouse}
  91. const
  92.   MouseChar  : Char = #04;
  93.   {$ENDIF}
  94.  
  95. {Color set used by entry screen}
  96. const
  97.   EsColors : ColorSet = (
  98.     TextColor       : $1A; TextMono        : $0F;
  99.     CtrlColor       : $1E; CtrlMono        : $08;
  100.     FrameColor      : $1A; FrameMono       : $0F;
  101.     HeaderColor     : $1F; HeaderMono      : $70;
  102.     ShadowColor     : $08; ShadowMono      : $0F;
  103.     HighlightColor  : $4F; HighlightMono   : $70;
  104.     PromptColor     : $1F; PromptMono      : $0F;
  105.     SelPromptColor  : $1F; SelPromptMono   : $0F;
  106.     ProPromptColor  : $17; ProPromptMono   : $07;
  107.     FieldColor      : $1A; FieldMono       : $07;
  108.     SelFieldColor   : $2F; SelFieldMono    : $70;
  109.     ProFieldColor   : $1B; ProFieldMono    : $07;
  110.     ScrollBarColor  : $13; ScrollBarMono   : $07;
  111.     SliderColor     : $13; SliderMono      : $0F;
  112.     HotSpotColor    : $30; HotSpotMono     : $70;
  113.     BlockColor      : $3E; BlockMono       : $0F;
  114.     MarkerColor     : $3F; MarkerMono      : $70;
  115.     DelimColor      : $1E; DelimMono       : $0F;
  116.     SelDelimColor   : $31; SelDelimMono    : $0F;
  117.     ProDelimColor   : $1E; ProDelimMono    : $0F;
  118.     SelItemColor    : $2F; SelItemMono     : $70;
  119.     ProItemColor    : $17; ProItemMono     : $07;
  120.     HighItemColor   : $1F; HighItemMono    : $0F;
  121.     AltItemColor    : $1F; AltItemMono     : $0F;
  122.     AltSelItemColor : $2F; AltSelItemMono  : $70;
  123.     FlexAHelpColor  : $1F; FlexAHelpMono   : $0F;
  124.     FlexBHelpColor  : $1F; FlexBHelpMono   : $0F;
  125.     FlexCHelpColor  : $1B; FlexCHelpMono   : $70;
  126.     UnselXrefColor  : $1E; UnselXrefMono   : $09;
  127.     SelXrefColor    : $5F; SelXrefMono     : $70;
  128.     MouseColor      : $4F; MouseMono       : $70);
  129.  
  130. {Entry field constants}
  131. const
  132.   idAcctNo               = 0;
  133.   idName                 = 1;
  134.   idCompany              = 2;
  135.   idAddress              = 3;
  136.   idCity                 = 4;
  137.   idState                = 5;
  138.   idZipCode              = 6;
  139.   idPhone                = 7;
  140.   idEntries              = 8;
  141.  
  142.   {these ID's are relative to the ID for the first field on a given row--see
  143.    PostEdit, below}
  144.   idQuantity             = 0;
  145.   idCost                 = 1;
  146.   idDescription          = 2;
  147.   idTotal                = 3;
  148.  
  149.   {Child window indexes}
  150.   cwMenu                 = 1;
  151.   cwSEntry               = 2;
  152.  
  153. {Menu item constants}
  154. const
  155.   miCalculate1    = 1;
  156.   miGross2        = 2;
  157.   miNet3          = 3;
  158.   miSearch4       = 4;
  159.   miAcct5         = 5;
  160.   miName6         = 6;
  161.   miCompany7      = 7;
  162.   miAddress8      = 8;
  163.   miCity9         = 9;
  164.   miState10       = 10;
  165.   miZip11         = 11;
  166.   miPhone12       = 12;
  167.   miHelp13        = 13;
  168.   miQuit14        = 14;
  169.  
  170. const
  171.   MaxEntries = 50;
  172. type
  173.   UserRecord =
  174.     record
  175.       AcctNo               : string[13];
  176.       Name                 : string[30];
  177.       Company              : string[35];
  178.       Address              : string[35];
  179.       City                 : string[25];
  180.       State                : string[15];
  181.       ZipCode              : string[10];
  182.       Phone                : string[14];
  183.     end;
  184.   EntryRec =
  185.     record
  186.       Quantity             : Word;
  187.       Cost                 : Real;
  188.       Description          : string[20];
  189.       Total                : Real;
  190.     end;
  191.   UserEntries = array[1..MaxEntries] of EntryRec;
  192. var
  193.   SES      : ScrollingEntryScreen;
  194.   ES       : EntryScreen;
  195.   MM       : Menu;
  196.   MP       : ^Menu;
  197.   UR       : UserRecord;
  198.   UE       : UserEntries;
  199.   I        : Word;
  200.   Status   : Word;
  201.   FramePos : FramePosType;
  202.   HotCode  : Byte;
  203.   BarPos   : LongInt;
  204.   Quit     : Boolean;
  205.   XAbs     : Integer;
  206.   YAbs     : Integer;
  207.   {$IFDEF TestStream}
  208.   S      : BufIdStream;
  209.   {$ENDIF}
  210.  
  211. function InitMenu(var M : Menu) : Word;
  212.   {-Initialize menu system generated by MAKEMENU}
  213. const
  214.   Frame1 : FrameArray = '╥╚╥╝─═║║';
  215.   WinOptions = wClear+wUserContents+wAllMouseEvents;
  216. begin
  217.   with M do begin
  218.     if not InitCustom(14, 4, 66, 4, EsColors, WinOptions, Horizontal) then begin
  219.       InitMenu := InitStatus;
  220.       Exit;
  221.     end;
  222.  
  223.     mnOptionsOn(
  224.       mnAlphaMatch+mnSelectOnMatch+mnAllowPending+mnArrowSelect+mnAllHotSpots);
  225.     mnOptionsOff(
  226.       mnPopOnSelect+mnUseItemForTopic+mnMainSelect+mnSelectOnClick);
  227.  
  228.     AddItem(' Calculate ', 2, 2, miCalculate1);
  229.       AddFramedSubMenu(16, 6, 22, 7, Vertical, Frame1);
  230.       AddItem('Gross', 1, 1, miGross2);
  231.       AddItem('Net', 2, 1, miNet3);
  232.       ItemsDone;
  233.     AddItem(' Search ', 14, 2, miSearch4);
  234.       AddFramedSubMenu(28, 6, 37, 13, Vertical, Frame1);
  235.       AddItem('Acct #', 1, 1, miAcct5);
  236.       AddItem('Name', 2, 1, miName6);
  237.       AddItem('Company', 3, 1, miCompany7);
  238.       AddItem('Address', 4, 1, miAddress8);
  239.       AddItem('City', 5, 1, miCity9);
  240.       AddItem('State', 6, 1, miState10);
  241.       AddItem('Zip code', 7, 1, miZip11);
  242.       AddItem('Phone', 8, 1, miPhone12);
  243.       ItemsDone;
  244.     AddItem(' Help ', 23, 2, miHelp13);
  245.     AddItem(' Quit ', 30, 2, miQuit14);
  246.     ItemsDone;
  247.  
  248.     InitMenu := RawError;
  249.   end;
  250. end;
  251.  
  252. {$F+}
  253. procedure PostEdit(ESP : EntryScreenPtr);
  254.   {-Called just after a field has been edited}
  255. var
  256.   Row : Word;
  257. begin
  258.   with ESP^ do
  259.     {do nothing if user didn't change the field}
  260.     if CurrentFieldModified then begin
  261.       {calculate the current row}
  262.       Row := Succ(GetCurrentID div 4);
  263.  
  264.       {which column is it?}
  265.       case GetCurrentID mod 4 of
  266.         {was the cost or quantity changed?}
  267.         idQuantity, idCost :
  268.           with UE[Row] do begin
  269.             {calculate Total for this row}
  270.             if (Quantity = 0) or (Cost = BadReal) then
  271.               Total := BadReal
  272.             else
  273.               Total := Quantity*Cost;
  274.  
  275.             {update the Total field for this row}
  276.             DrawField((Pred(Row)*4)+idTotal);
  277.           end;
  278.       end;
  279.     end;
  280. end;
  281. {$F-}
  282.  
  283. function InitScrollingEntryScreen : Word;
  284.   {-Initialize the scrolling entry screen}
  285. const
  286.   WinOptions = wClear+wUserContents+wAllMouseEvents+wNoCoversBuffer;
  287. var
  288.   Row : Word;
  289. begin
  290.   with SES do begin
  291.     if not InitCustom(14, 16, 66, 21, EsColors, WinOptions) then begin
  292.       InitScrollingEntryScreen := InitStatus;
  293.       Exit;
  294.     end;
  295.  
  296.     {stop at the bottom of the entry screen, but allow exiting at the top}
  297.     SetWrapMode(ExitAtTop);
  298.  
  299.     {install post-edit routine to handle the calculated field}
  300.     SetPostEditProc(PostEdit);
  301.  
  302.     esFieldOptionsOn(efClearFirstChar);
  303.     for Row := 1 to MaxEntries do
  304.       with UE[Row] do begin
  305.         {idQuantity:}
  306.           esFieldOptionsOn(efRightJustify);
  307.           esSecFieldOptionsOn(sefSuppressZero);
  308.           AddWordField(
  309.             LeftPad(Long2Str(Row), 2), Row, 2,
  310.             '999', Row, 6,
  311.             9, 0, 65535, Quantity);
  312.           esFieldOptionsOff(efRightJustify);
  313.           esSecFieldOptionsOff(sefSuppressZero);
  314.  
  315.         {idCost:}
  316.           esFieldOptionsOn(efRightJustify);
  317.           AddRealField(
  318.             '', Row, 11,
  319.             '$999.99', Row, 11,
  320.             10, -1.5E+38,  1.5E+38, 0, Cost);
  321.           esFieldOptionsOff(efRightJustify);
  322.  
  323.         {idDescription:}
  324.           AddStringField(
  325.             '', Row, 20,
  326.             'XXXXXXXXXXXXXXXXXXXX', Row, 20, 20,
  327.             11, Description);
  328.  
  329.         {idTotal:}
  330.           esFieldOptionsOn(efRightJustify+efProtected);
  331.           AddRealField(
  332.             '', Row, 42,
  333.             '$999,999.99', Row, 42,
  334.             12, -1.5E+38,  1.5E+38, 0, Total);
  335.           esFieldOptionsOff(efRightJustify+efProtected);
  336.       end;
  337.  
  338.     {allocate the virtual screen}
  339.     AllocateScreen;
  340.  
  341.     InitScrollingEntryScreen := RawError;
  342.   end;
  343. end;
  344.  
  345. function InitEntryScreen : Word;
  346.   {-Initialize main entry screen}
  347. const
  348.   Frame1 = '┌└┐┘──││';
  349.   WinOptions = wBordered+wClear+wUserContents+wAllMouseEvents;
  350. begin
  351.   with ES, EsColors do begin
  352.     if not InitCustom(14, 6, 66, 21, EsColors, WinOptions) then begin
  353.       InitEntryScreen := InitStatus;
  354.       Exit;
  355.     end;
  356.  
  357.     {make room for the menu up at the top}
  358.     with wFrame do
  359.       AdjustFrameCoords(frXL, frYL-2, frXH, frYH);
  360.  
  361.     {add the menu as a regular child window, not a field}
  362.     AddChild(@MM);
  363.  
  364.     wFrame.SetFrameType(Frame1);
  365.     wFrame.AddShadow(shBR, shSeeThru);
  366.     wFrame.AddHeader(' Customer Data ', heTC);
  367.  
  368.   {$IFDEF UseHotSpots}
  369.     {add a hot spot at the top left corner}
  370.     wFrame.AddCustomHeader('[',   frTL,  1, 0, FrameColor, FrameMono);
  371.     wFrame.AddCustomHeader('■', frTL,  2, 0, FrameColor, FrameMono);
  372.     wFrame.AddCustomHeader(']',   frTL,  3, 0, FrameColor, FrameMono);
  373.     wFrame.AddHotRegion(frTL, hsRegion0, 2, 0, 1, 1);   {Close}
  374.   {$ENDIF}
  375.  
  376.     {separate the menu from the main entry screen}
  377.     wFrame.AddSpanHeader('├', '─', '┤', 02, frTT);
  378.  
  379.     {separate the child entry screen from the parent}
  380.     wFrame.AddSpanHeader('├', '─', '┤', 11, frTT);
  381.  
  382.     {label the columns of the scrollable entry screen}
  383.     AddTextFieldCustom(
  384.       'Qty    Cost   Description                 Total', 10, 6,
  385.       HeaderColor, HeaderMono);
  386.  
  387.     {don't wrap at edges of the entry screen}
  388.     SetWrapMode(StopAtEdges);
  389.  
  390.     esFieldOptionsOn(efClearFirstChar);
  391.  
  392.   {idAcctNo:}
  393.     AddStringField(
  394.       'Acct #', 1, 4,
  395.       '999-99-9999-9', 1, 12, 13,
  396.       1, UR.AcctNo);
  397.  
  398.   {idName:}
  399.     AddStringField(
  400.       'Name', 2, 6,
  401.       CharStr('x', 30), 2, 12, 30,
  402.       2, UR.Name);
  403.  
  404.   {idCompany:}
  405.     AddStringField(
  406.       'Company', 3, 3,
  407.       CharStr('x', 35), 3, 12, 35,
  408.       3, UR.Company);
  409.  
  410.   {idAddress:}
  411.     AddStringField(
  412.       'Address', 4, 3,
  413.       CharStr('x', 35), 4, 12, 35,
  414.       4, UR.Address);
  415.  
  416.   {idCity:}
  417.     AddStringField(
  418.       'City', 5, 6,
  419.       CharStr('x', 25), 5, 12, 25,
  420.       5, UR.City);
  421.  
  422.   {idState:}
  423.     AddStringField(
  424.       'State', 6, 5,
  425.       'xxxxxxxxxxxxxxx', 6, 12, 15,
  426.       6, UR.State);
  427.  
  428.   {idZipCode:}
  429.     AddStringField(
  430.       'Zip code', 7, 2,
  431.       '99999-9999', 7, 12, 10,
  432.       7, UR.ZipCode);
  433.  
  434.   {idPhone:}
  435.     AddStringField(
  436.       'Phone', 8, 5,
  437.       '(999) 999-9999', 8, 12, 14,
  438.       8, UR.Phone);
  439.  
  440.   {idEntries:}
  441.     AddWindowField(
  442.       '', 11, 1,
  443.       11, 1,
  444.       9, SES);
  445.  
  446.     InitEntryScreen := RawError;
  447.   end;
  448. end;
  449.  
  450. procedure InvokeMenu;
  451.   {-Invoke the menu}
  452. var
  453.   SaveChild : WindowPtr;
  454.   ID, Cmd : Word;
  455. begin
  456.   {save the active child window}
  457.   SaveChild := ES.ActiveChild;
  458.  
  459.   {activate the menu}
  460.   ES.SetActiveChild(MP);
  461.  
  462.   {get a choice from the menu, which is now the active child}
  463.   ES.Process;
  464.  
  465.   Cmd := ES.GetLastCommand;
  466.   case Cmd of
  467.     ccSelect :
  468.       Quit := (MP^.MenuChoice = miQuit14);
  469.     {$IFDEF UseMouse}
  470.     ccMouseDown,
  471.     ccMouseSel :
  472.       begin
  473.         {get absolute mouse coordinates}
  474.         XAbs := MouseKeyWordX+MouseXLo;
  475.         YAbs := MouseKeyWordY+MouseYLo;
  476.  
  477.         {evaluate the position of the mouse when it was clicked}
  478.         ES.EvaluatePos(XAbs, YAbs);
  479.         BarPos := ES.PosResults(FramePos, HotCode);
  480.  
  481.         {was it clicked on the hot spot?}
  482.         if HotCode = hsRegion0 then
  483.           Quit := True
  484.         else
  485.           ES.SetNextField(ES.EvaluateCommand(Cmd));
  486.       end;
  487.     {$ENDIF}
  488.   end;
  489.  
  490.   if not Quit then begin
  491.     {erase the menu}
  492.     MP^.EraseAllSubMenus(False, True);
  493.  
  494.     {restore the active child}
  495.     ES.SetActiveChild(SaveChild);
  496.   end;
  497. end;
  498.  
  499. {$IFDEF TestStream}
  500.  
  501. procedure RegisterTypes(var S : IdStream);
  502.   {-Register data types and pointers}
  503. begin
  504.   {register entry screen}
  505.   S.RegisterHier(ScrollingEntryScreenStream);
  506.  
  507.   {register field types}
  508.   S.RegisterHier(RealFieldStream);
  509.   S.RegisterHier(StringFieldStream);
  510.   S.RegisterHier(WordFieldStream);
  511.   S.RegisterHier(WindowFieldStream);
  512.  
  513.   {register user records}
  514.   S.RegisterPointer(1000, @UR);
  515.   S.RegisterPointer(1001, @UE);
  516.  
  517.   {register user-written routines}
  518.   S.RegisterPointer(1002, @PostEdit);
  519.  
  520.   {register the menu system}
  521.   S.RegisterHier(MenuStream);
  522. end;
  523.  
  524. {$ENDIF}
  525.  
  526. begin
  527.   {initialize user records}
  528.   FillChar(UR, SizeOf(UR), 0);
  529.   FillChar(UE, SizeOf(UE), 0);
  530.   for I := 1 to MaxEntries do
  531.     with UE[I] do begin
  532.       Cost := BadReal;
  533.       Total := BadReal;
  534.     end;
  535.  
  536.   {initialize menu}
  537.   Status := InitMenu(MM);
  538.   if Status <> 0 then begin
  539.     WriteLn('MM init error: ', Status);
  540.     Halt(1);
  541.   end;
  542.  
  543.   {initialize scrolling entry screen}
  544.   Status := InitScrollingEntryScreen;
  545.   if Status <> 0 then begin
  546.     WriteLn('SES init error: ', Status);
  547.     Halt(1);
  548.   end;
  549.  
  550.   {initialize main entry screen}
  551.   Status := InitEntryScreen;
  552.   if Status <> 0 then begin
  553.     WriteLn('ES init error: ', Status);
  554.     Halt(1);
  555.   end;
  556.  
  557. {$IFDEF TestStream}
  558.  
  559.   {set user record for both entry screens}
  560.   ES.SetUserRecord(UR, SizeOf(UR));
  561.   SES.SetUserRecord(UE, SizeOf(UE));
  562.  
  563.   {create stream file}
  564.   S.Init('WFIELD4.STM', SCreate, 4096);
  565.  
  566.   {register types and store the entry screen}
  567.   RegisterTypes(S);
  568.   S.Put(ES);
  569.   Status := S.GetStatus;
  570.   if Status <> 0 then begin
  571.     WriteLn('Store error: ', Status);
  572.     Halt(2);
  573.   end;
  574.   S.Done;
  575.  
  576.   {dispose of the parent *and* its children}
  577.   ES.Done;
  578.  
  579.   {reopen stream file}
  580.   S.Init('WFIELD4.STM', SOpen, 4096);
  581.  
  582.   {register types and load the entry screen}
  583.   RegisterTypes(S);
  584.   S.Get(ES);
  585.   Status := S.GetStatus;
  586.   if Status <> 0 then begin
  587.     WriteLn('Load error: ', Status);
  588.     Halt(3);
  589.   end;
  590.   S.Done;
  591.  
  592.   {get index for child window}
  593.   MP := MenuPtr(ES.ChildPtr(cwMenu));
  594. {$ELSE}
  595.   MP := @MM;
  596. {$ENDIF}
  597.  
  598.   {clear the screen}
  599.   TextChar := #178;
  600.   TextAttr := 7;
  601.   ClrScr;
  602.  
  603.   {F10 activates menu}
  604.   EntryCommands.AddCommand(ccUser0, 1, $4400, 0);
  605.  
  606.   {F10 deactivates menu}
  607.   MenuCommands.AddCommand(ccQuit, 1, $4400, 0);
  608.  
  609.   {$IFDEF UseMouse}
  610.   if MouseInstalled then
  611.     with EsColors do begin
  612.       {activate mouse cursor}
  613.       SoftMouseCursor($0000, (ColorMono(MouseColor, MouseMono) shl 8)+
  614.                              Byte(MouseChar));
  615.       ShowMouse;
  616.  
  617.       {enable mouse support}
  618.       EntryCommands.cpOptionsOn(cpEnableMouse);
  619.       MenuCommands.cpOptionsOn(cpEnableMouse);
  620.     end;
  621.   {$ENDIF}
  622.  
  623.   {test entry screen}
  624.   Quit := False;
  625.   repeat
  626.     ES.Process;
  627.     case ES.GetLastCommand of
  628.       ccUser0 :
  629.         InvokeMenu;
  630.       {$IFDEF UseMouse}
  631.       ccMouseDown,
  632.       ccMouseSel :
  633.         begin
  634.           {get absolute mouse coordinates}
  635.           XAbs := MouseKeyWordX+MouseXLo;
  636.           YAbs := MouseKeyWordY+MouseYLo;
  637.  
  638.           {evaluate the position of the mouse when it was clicked}
  639.           ES.EvaluatePos(XAbs, YAbs);
  640.           BarPos := ES.PosResults(FramePos, HotCode);
  641.  
  642.           {was it clicked on one of the menu choices?}
  643.           if (FramePos = frInsideFrame) and MP^.SelectItemByPos(XAbs, YAbs) then
  644.             InvokeMenu
  645.           else
  646.             {was it clicked on the hot spot?}
  647.             Quit := (HotCode = hsRegion0);
  648.         end;
  649.       {$ENDIF}
  650.       else Quit := True;
  651.     end;
  652.   until Quit;
  653.  
  654.   {erase entry screen}
  655.   ES.Erase;
  656.  
  657.   {$IFDEF UseMouse}
  658.   HideMouse;
  659.   {$ENDIF}
  660.  
  661.   {show exit command}
  662.   ClrScr;
  663.   WriteLn('Exit command = ', ES.GetLastCommand);
  664.  
  665.   {dispose of the parent *and* its children}
  666.   ES.Done;
  667. end.
  668.